
"""销售预留功能"""

from odoo import models, api, fields
from odoo.tools import float_compare
from odoo.exceptions import UserError, ValidationError


class Picking(models.Model):
    _inherit = 'stock.picking'

    @api.multi
    def action_cancel(self):
        """销售单上预留的，需要在确认出库单时的解除预留。"""
        for pick in self:
            sale_id = pick.sale_id
            if sale_id:
                if sale_id.is_reserved:
                    sale_id.nd_unreserve()
        return super().action_cancel()


class StockMoveLine(models.Model):
    _inherit = 'stock.move.line'

    def _action_done(self):
        """销售单上预留的，需要在确认出库单时的解除预留。"""
        for line in self:
            if line.picking_id and line.picking_id.sale_id:
                sale_id = line.picking_id.sale_id
                if sale_id.is_reserved:
                    sale_id.nd_unreserve()
        return super()._action_done()


class SaleOrder(models.Model):
    _inherit = 'sale.order'

    is_reserved = fields.Boolean('是否已保留')

    def nd_reserve(self):
        """针对此张销售单进行保留操作"""
        for order in self:
            for line in order.order_line:
                line._do_reserve()
            order.is_reserved = True

    def nd_unreserve(self):
        """针对此张销售单进行取消保留操作"""
        for order in self:
            for line in order.order_line:
                line._do_unreserve()
            order.is_reserved = False


class SaleOrderLine(models.Model):
    _inherit = 'sale.order.line'

    nd_reserved_qty = fields.Float('预留数量')
    nd_reserved_qty_show = fields.Float('预留数量', compute="_compute_nd_reserved_qty_show", store=True)
    is_reserved = fields.Boolean('是否已保留', related="order_id.is_reserved", store=True)

    @api.depends('nd_reserved_qty', 'nd_lot_lines.reserved_qty')
    def _compute_nd_reserved_qty_show(self):
        for line in self:
            if line.product_id.tracking == 'lot':
                line.nd_reserved_qty_show = sum(line.nd_lot_lines.mapped('reserved_qty'))
            else:
                line.nd_reserved_qty_show = line.nd_reserved_qty

    def _get_all_locations(self):
        """获取所有可以出库的库位"""
        location_ids = self.env['stock.location'].search([('usage', '=', 'internal'), ('scrap_location', '=', False)])
        return location_ids

    def get_available_qty(self):
        """获取当前销售明细产品的可用量"""
        self.ensure_one()
        product_id = self.product_id

        available_qty = 0
        Quant = self.env['stock.quant']
        # TODO 待优化!
        if product_id.tracking == 'lot':
            for lot_line in self.nd_lot_lines:
                available_qty += Quant._get_available_quantity(product_id, lot_line.location_src_id,
                                                               lot_id=lot_line.lot_id)
        else:
            # TODO 针对没有批次管理的（主要没有指明出货库位的），如何处理？
            for location_id in self._get_all_locations():
                available_qty += Quant._get_available_quantity(product_id, location_id)
        return available_qty

    def _do_reserve(self):
        """执行保留操作"""
        Quant = self.env['stock.quant']
        lot_manage = self.product_id.tracking == 'lot'

        lot_ids = self.nd_lot_lines.mapped('lot_id')
        available_qty = self.get_available_qty()
        if available_qty >= self.product_uom_qty:
            if lot_manage:
                for lot_line in self.nd_lot_lines:
                    quants = Quant._update_reserved_quantity(
                        self.product_id, lot_line.location_src_id, (lot_line.qty - lot_line.reserved_qty),
                        lot_id=lot_line.lot_id,
                    )
                    lot_line.reserved_qty += sum([quant[1] for quant in quants])
            else:
                total = self.product_uom_qty - self.nd_reserved_qty
                reserved_qty = 0
                for location_id in self._get_all_locations():
                    if total > 0:
                        quants = Quant._update_reserved_quantity(self.product_id, location_id, total)
                        reserved_quant_qty = sum([quant[1] for quant in quants])
                        total -= reserved_quant_qty
                        reserved_qty += reserved_quant_qty
                self.nd_reserved_qty += reserved_qty
        else:
            if lot_manage:
                raise UserError(f'产品"{self.product_id.display_name}"在相应的批次"{lot_ids.mapped("name")}"上的可用数量{(available_qty)}不足!')
            else:
                raise UserError(f'产品"{self.product_id.display_name}"可用数量不足!')

    def _do_unreserve(self):
        """执行取消保留"""
        lot_manage = self.product_id.tracking == 'lot'
        Quant = self.env['stock.quant']
        if lot_manage:
            for line in self.nd_lot_lines:
                Quant._update_reserved_quantity(self.product_id, line.location_src_id, -line.reserved_qty,
                                                lot_id=line.lot_id, strict=True)
                line.reserved_qty = 0
        else:
            total_reserved_qty = self.nd_reserved_qty
            for location_id in self._get_all_locations():
                quants = Quant._gather(self.product_id, location_id, strict=True)
                available_quantity = min(sum(quants.mapped('reserved_quantity')), total_reserved_qty)
                if total_reserved_qty > 0 and available_quantity > 0:
                    # quants = Quant._update_reserved_quantity(self.product_id, location_id, -total_reserved_qty,
                    #                                          strict=True)
                    quants = Quant._update_reserved_quantity(self.product_id, location_id, -available_quantity,
                                                             strict=True)
                    released_qty = sum([quant[1] for quant in quants])
                    total_reserved_qty += released_qty  # 负值
                    self.nd_reserved_qty += released_qty


class SalrOrderLineLot(models.Model):
    _inherit = 'nd.sale.line.lot'

    reserved_qty = fields.Float('已预留数量', readonly=True)
